package com.soft.zosagent.client;

import com.google.gson.Gson;
import com.soft.zosagent.common.*;
import com.soft.zosagent.pojo.BaseFileInfo;
import com.soft.zosagent.pojo.Request;
import com.soft.zosagent.pojo.Response;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import org.apache.commons.lang3.StringUtils;

/**
 * 
 * @author huisong
 * 
 */
public class ClientHandler extends ChannelInboundHandlerAdapter {
	/**
	 * Creates a client-side handler.
	 */

	Client client;

	Request currentRequest;

	boolean loginStatus=false;


	private String LINEFEED = System.getProperty("line.separator");

	BaseFileInfo localFileInfo;
	BaseFileInfo remoteFileInfo;

	//专门给写数据的时候使用，错误一般发生在client运行在主机端
	private boolean clientErrorStatus = false;

	public void setLocalFileInfo(BaseFileInfo localFileInfo) {
		this.localFileInfo = localFileInfo;
		internalFileInfo.localFileName = localFileInfo.getFileName();
	}




	InternalFileInfo internalFileInfo = new InternalFileInfo();

	public class InternalFileInfo{
		public String localFileName;
		public String fileType;
		public String writerType;
		public Object fileWriter;
		public int lrecl=0;
		public String recfm="";
		public boolean needCodeConvert = false;
		public String srcCharset;
		public String tgtCharset;
		public long writeBytes=0;

	}



	public ClientHandler(Client client ) {
		this.client = client;
	}

	@Override
	public void channelActive(ChannelHandlerContext ctx) {
		ctx.channel().attr(Constant.UNIQUE_ID).set(client.getUniqueId());

	}


	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg)
			throws Exception {
		// LoggerPrint.LoggerPrint.consoleLog(msg.toString());
		if (msg instanceof Response) {

			Response resp = (Response) msg;
			currentRequest = resp.getReq();
			LoggerPrint.consoleLog("Response content:"+(new Gson()).toJson(resp),LogLevel.DEBUG);

			Request req = resp.getReq();
			ACTION action = req.getAction();
			client.setRtnMsg(resp.getResMessage());
			//专门第一次登陆用。
			if(action == ACTION.ACTION_USER_LOGIN){
				//密码登陆时，确认服务器的类型。
				Client.CLIENT_STATIC_DATA.ServerOsType = resp.getOsType();

				if(resp.getResCode().equals(Constant.SuccessCode)) {
					loginStatus = true;
					Client.CLIENT_STATIC_DATA.loginStatus = true;

				}else{
					LoggerPrint.consoleLog("Server response failed. msg:"+resp.getResMessage(),LogLevel.DEBUG);
					client.setExitCode(8);
					loginStatus = false;
					Client.CLIENT_STATIC_DATA.loginStatus = false;

				}
				//通知主函数，已经验证完毕
				Client.CLIENT_STATIC_DATA.semaphoreForLogin.release();
				return;
			}


			if(resp.getResCode().equals(Constant.SuccessCode)) {
//				if(StringUtils.isNotEmpty(resp.getResMessage())){
//					LoggerPrint.consoleLog(resp.getResMessage(),LogLevel.INFO);
//				}
				LoggerPrint.consoleLog("Server response ok.",LogLevel.INFO);
				if(action == ACTION.ACTION_SENDJOB){
					//释放锁，为了同步操作使用的。
					LoggerPrint.consoleLog("job is submited. JobId:"+resp.getResMessage(),LogLevel.INFO);
					client.releaseWorkerLock();
				}else if(action == ACTION.ACTION_QRYJOB){
					LoggerPrint.consoleLog(req.getJobName()+"("+req.getJobId()+") status:"+resp.getResMessage(),LogLevel.INFO);
					client.releaseWorkerLock();
				}else if(action == ACTION.ACTION_RECVJOB){
					LoggerPrint.consoleLog(req.getJobName()+"("+req.getJobId()+") jobOutput:"+resp.getResMessage(),LogLevel.INFO);
					client.releaseWorkerLock();
				}else if(action == ACTION.ACTION_CANCELJOB){
					LoggerPrint.consoleLog(req.getJobName()+"("+req.getJobId()+") canceled:"+resp.getResMessage(),LogLevel.INFO);
					client.releaseWorkerLock();
				}

			}
			else if(resp.getResCode().equals(Constant.FAILCode)){
				LoggerPrint.consoleLog("Server response failed. msg:"+resp.getResMessage(),LogLevel.ERROR);
				client.setExitCode(8);
				ctx.channel().close().sync();
				client.releaseWorkerLock();
			}
			else{
				throw new RuntimeException("invalid response code.["+resp.getResCode()+"]");
			}
		}
		else{
			LoggerPrint.consoleLog("strange object.",LogLevel.ERROR);
		}
	}

	private void resetInternalFileInfo(InternalFileInfo internalFileInfo) {
		internalFileInfo.needCodeConvert = false;
		internalFileInfo.tgtCharset = "";
		internalFileInfo.srcCharset ="";
		internalFileInfo.localFileName = "";
		internalFileInfo.fileType = "";
		internalFileInfo.writerType = "";
		internalFileInfo.lrecl=0;
		internalFileInfo.recfm = "";
		internalFileInfo.writeBytes = 0;
	}

	private void checkFileType(String localFilePath) {
		if (localFilePath.matches(".*/.*")) {
			if (!localFilePath.startsWith("/") && !localFilePath.contains(":")) {
				throw new RuntimeException("not a valid unix fileName");
			} else {
				internalFileInfo.fileType = Constant.UNIX_FILE;
			}
		} else if (localFilePath.matches(".*:/.*")
				|| localFilePath.matches(".*:\\.*")
				|| localFilePath.matches(".*:\\\\.*")
		) {
			//windows file
			internalFileInfo.fileType = Constant.WINDOWS_FILE;

		} else if (localFilePath.matches(Constant.ZOSFILEPARTEN2) || localFilePath.matches(Constant.ZOSFILEPARTEN1)) {
			//zos 文件
			internalFileInfo.fileType = Constant.ZOS_FILE;
		} else {
			throw new RuntimeException("not support fileName. [" + localFilePath + "]");
		}

	}


	@Override
	public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
		ctx.flush();
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
		cause.printStackTrace();
		LoggerPrint.consoleLog("socket exceptionCauth",LogLevel.ERROR);
		client.setExitCode(8);
		client.releaseWorkerLock();
		ctx.close();
	}

	@Override
	public void channelInactive(ChannelHandlerContext ctx) throws Exception {
		super.channelInactive(ctx);
		LoggerPrint.consoleLog("client disconnect from Server.",LogLevel.INFO);

	}

	@Override
	public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
		//System.out.println(ctx.channel().isWritable());

		ctx.fireChannelWritabilityChanged();
		//System.out.println(ctx.channel().isWritable());
	}
}
